package top.kpromise.user.controller;

import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import top.kpromise.user.data.Config;
import top.kpromise.user.model.response.UserLoginModel;
import top.kpromise.user.model.response.UserModel;
import top.kpromise.user.model.response.UserTicketModel;
import top.kpromise.user.response.Result;
import top.kpromise.user.service.UserLoginService;
import top.kpromise.user.service.UserService;
import top.kpromise.user.service.UserTicketService;
import top.kpromise.user.service.VerifyCodeService;
import top.kpromise.user.utils.RandomUtils;
import top.kpromise.user.utils.SecurityUtils;

import java.util.Map;

@RestController
@RequestMapping("/user/security")
public class UserSecurityController {

    private final UserService userService;
    private final UserLoginService userLoginService;
    private final UserTicketService userTicketService;
    private final VerifyCodeService verifyCodeService;

    public UserSecurityController(UserService userService, VerifyCodeService verifyCodeService,
                                  UserTicketService userTicketService, UserLoginService userLoginService) {
        this.userService = userService;
        this.verifyCodeService = verifyCodeService;
        this.userTicketService = userTicketService;
        this.userLoginService = userLoginService;
    }

    private Map<String, Object> changLoginValueCode(String userId, boolean isPhone) {
        UserModel userModel = userService.findUserById(userId);
        if (userModel == null) {
            return Result.error("未查询到用户");
        }
        String code = RandomUtils.verifyCode(Config.SMS_LEN);
        String loginValue = isPhone ? userModel.getPhone() : userModel.getEmail();
        userService.sendChangeLoginValueCode(loginValue, code);
        return Result.data(null, "验证码发送成功");
    }

    @RequestMapping("/changePhoneCode")
    public Map<String, Object> changePhoneCode(@RequestHeader("userId") String userId) {
        return changLoginValueCode(userId, true);
    }

    @RequestMapping("/changeEmailCode")
    public Map<String, Object> changeEmailCode(@RequestHeader("userId") String userId) {
        return changLoginValueCode(userId, false);
    }

    private Map<String, Object> changeLoginValueTicket(String userId, String verifyCode, boolean isPhone) {
        if (userId == null) {
            return Result.error("用户未登录");
        }
        UserModel userModel = userService.findUserById(userId);
        Map<String, Object> map;
        int type;
        if (isPhone) {
            map = verifyCodeService.checkVerifyCode(userModel.getPhone(),
                    verifyCode, Config.VerifyCodeType.changeLoginPhone);
            type = Config.TicketType.changePhone;
        } else {
            map = verifyCodeService.checkVerifyCode(userModel.getEmail(),
                    verifyCode, Config.VerifyCodeType.changeLoginEmail);
            type = Config.TicketType.changeEmail;
        }
        if (map != null) {
            return map;
        }
        String ticket = RandomUtils.ticket();
        UserTicketModel userTicketModel = new UserTicketModel();
        userTicketModel.setUserId(userId);
        userTicketModel.setTicket(ticket);
        userTicketModel.setType(type);
        userTicketService.saveTicket(userTicketModel);
        return Result.data(ticket, "验证码正确");
    }

    @RequestMapping("/changePhoneTicket")
    public Map<String, Object> changePhoneTicket(@RequestHeader("userId") String userId, String verifyCode) {
        return changeLoginValueTicket(userId, verifyCode, true);
    }

    @RequestMapping("/changeEmailTicket")
    public Map<String, Object> changeEmailTicket(@RequestHeader("userId") String userId, String verifyCode) {
        return changeLoginValueTicket(userId, verifyCode, false);
    }

    @RequestMapping("/bindNewLoginValueCode")
    public Map<String, Object> bindNewPhoneCode(String loginValue) {
        String verifyCode = RandomUtils.verifyCode(Config.SMS_LEN);
        userService.sendBindNewLoginValueCode(loginValue, verifyCode);
        return Result.data(null, "验证码发送成功");
    }

    private Map<String, Object> changeLoginValue(String userId, String ticket, String newLoginValue, String verifyCode) {
        if (userId == null) {
            return Result.error("用户未登录");
        }
        UserTicketModel userTicketModel = userTicketService.findByTicket(ticket);
        int ticketType = userTicketModel.getType();
        int verifyCodeType = Config.VerifyCodeType.changeLoginEmail;
        String successMsg = "邮箱修改成功";
        if (ticketType == Config.TicketType.changePhone) {
            verifyCodeType = Config.VerifyCodeType.changeLoginPhone;
            successMsg = "手机号修改成功";
        }
        Map<String, Object> map = userTicketService.checkTicket(ticket, userId, ticketType);
        if (map != null) {
            return map;
        }
        map = verifyCodeService.checkVerifyCode(newLoginValue, verifyCode, verifyCodeType);
        if (map != null) {
            return map;
        }
        userService.updateLoginValue(userId, newLoginValue);
        userTicketService.deleteByTicket(ticket);
        return Result.data(null, successMsg);
    }

    @RequestMapping("/changeLoginValue")
    @Transactional
    public Map<String, Object> changeEmail(@RequestHeader("userId") String userId, String ticket, String newLoginValue,
                                           String verifyCode) {
        return changeLoginValue(userId, ticket, newLoginValue, verifyCode);
    }

    @RequestMapping("/resetPasswordCode")
    public Map<String, Object> resetPasswordCode(String loginValue) {
        if (loginValue == null) {
            return Result.error("请输入手机号或邮箱");
        }
        UserModel userModel = userService.findUserByLoginValue(loginValue);
        if (userModel == null) {
            return Result.error("该用户不存在");
        }
        if (userModel.getEnabled() == 0) {
            return Result.error("用户未激活，请先激活");
        }
        String verifyCode = RandomUtils.verifyCode(Config.SMS_LEN);
        userService.sendResetPasswordCode(loginValue, verifyCode);
        return Result.data(null, "验证码发送成功");
    }

    @RequestMapping("/resetPassword")
    @Transactional
    public Map<String, Object> resetPassword(String verifyCode, String loginValue, String password, String passwordAgain) {
        if (password == null || password.length() != Config.passwordLen) {
            return Result.error("密码长度是 " + Config.passwordLen + " 位");
        }
        if (!password.equals(passwordAgain)) {
            return Result.error("两次密码输入不一致");
        }
        Map<String, Object> map = verifyCodeService.checkVerifyCode(loginValue, verifyCode, Config.VerifyCodeType.resetPassword);
        if (map != null) {
            return map;
        }
        UserModel userModel = userService.findUserByLoginValue(loginValue);
        UserLoginModel userLoginModel = userLoginService.findUser(userModel.getId(), Config.LoginType.PASSWORD);
        userLoginModel.setLoginValue(password);
        userLoginService.updateByUserId(userLoginModel.getUserId(), SecurityUtils.md5(password, Config.PASSWORD_SALT),
                Config.LoginType.PASSWORD);
        return Result.data(null, "密码重置成功");
    }
}
